using Microsoft.Extensions.Logging;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using ReactiveChannelMessaging.Core;
using ReactiveChannelMessaging.Communication;

namespace ReactiveChannelMessaging.Examples;

/// <summary>
/// 通讯管理器 - 统一管理串口、TCP、UDP通讯
/// </summary>
public class CommunicationManager : IAsyncDisposable
{
    private readonly ILogger<CommunicationManager> _logger;
    private readonly ReactiveMessageBus _messageBus;
    private readonly Dictionary<string, ReactiveSerialCommunication> _serialPorts;
    private readonly Dictionary<string, ReactiveTcpCommunication> _tcpConnections;
    private readonly Dictionary<string, ReactiveUdpCommunication> _udpConnections;
    private readonly Subject<string> _statusSubject;
    private readonly List<IDisposable> _subscriptions;
    
    // 动态的数据流管理
    private readonly Subject<SerialDataMessage> _serialDataSubject;
    private readonly Subject<TcpDataMessage> _tcpDataSubject;
    private readonly Subject<UdpDataMessage> _udpDataSubject;

    /// <summary>
    /// 获取串口通信实例字典（仅供内部使用）
    /// </summary>
    internal IReadOnlyDictionary<string, ReactiveSerialCommunication> SerialPorts => _serialPorts;

    public CommunicationManager(
        ILogger<CommunicationManager> logger,
        ReactiveMessageBus messageBus)
    {
        _logger = logger;
        _messageBus = messageBus;
        _serialPorts = new Dictionary<string, ReactiveSerialCommunication>();
        _tcpConnections = new Dictionary<string, ReactiveTcpCommunication>();
        _udpConnections = new Dictionary<string, ReactiveUdpCommunication>();
        _statusSubject = new Subject<string>();
        _subscriptions = new List<IDisposable>();
        
        // 初始化动态数据流主题
        _serialDataSubject = new Subject<SerialDataMessage>();
        _tcpDataSubject = new Subject<TcpDataMessage>();
        _udpDataSubject = new Subject<UdpDataMessage>();
    }

    /// <summary>
    /// 串口数据接收流 - 使用动态主题
    /// </summary>
    public IObservable<SerialDataMessage> SerialDataReceived => _serialDataSubject.AsObservable();

    /// <summary>
    /// TCP数据接收流 - 使用动态主题
    /// </summary>
    public IObservable<TcpDataMessage> TcpDataReceived => _tcpDataSubject.AsObservable();

    /// <summary>
    /// UDP数据接收流 - 使用动态主题
    /// </summary>
    public IObservable<UdpDataMessage> UdpDataReceived => _udpDataSubject.AsObservable();

    /// <summary>
    /// 连接状态变化流
    /// </summary>
    public IObservable<string> ConnectionStatusChanged => _statusSubject.AsObservable();

    /// <summary>
    /// 初始化通讯管理器
    /// </summary>
    public async Task InitializeAsync()
    {
        SetupStatusMonitoring();
        _logger.LogInformation("Communication manager initialized");
        await Task.CompletedTask;
    }

    #region Serial Communication Methods

    /// <summary>
    /// 打开串口
    /// </summary>
    public async Task<bool> OpenSerialPortAsync(string portName, int baudRate)
    {
        try
        {
            if (_serialPorts.ContainsKey(portName))
            {
                _logger.LogWarning("Serial port {PortName} is already open", portName);
                return true;
            }

            var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
            var serialComm = new ReactiveSerialCommunication(
                portName, 
                baudRate, 
                loggerFactory.CreateLogger<ReactiveSerialCommunication>(),
                _messageBus);

            var success = await serialComm.OpenAsync();
            if (success)
            {
                _serialPorts[portName] = serialComm;
                
                // 设置串口数据转发 - 将个别串口的数据转发到统一的主题
                var dataSubscription = serialComm.ReceivedData
                    .Subscribe(
                        data => _serialDataSubject.OnNext(data),
                        error => _logger.LogError(error, "Error in serial data stream for port {PortName}", portName)
                    );
                _subscriptions.Add(dataSubscription);
                
                SetupSerialMonitoring(serialComm);
                _statusSubject.OnNext($"Serial port {portName} opened at {baudRate} baud");
                _logger.LogInformation("Serial port {PortName} data subscription established", portName);
            }

            return success;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to open serial port {PortName}", portName);
            return false;
        }
    }

    /// <summary>
    /// 关闭串口
    /// </summary>
    public async Task CloseSerialPortAsync(string portName)
    {
        if (_serialPorts.TryGetValue(portName, out var serialComm))
        {
            await serialComm.CloseAsync();
            await serialComm.DisposeAsync();
            _serialPorts.Remove(portName);
            _statusSubject.OnNext($"Serial port {portName} closed");
            _logger.LogInformation("Serial port {PortName} closed and removed from collection", portName);
        }
    }

    /// <summary>
    /// 发送串口字符串数据
    /// </summary>
    public async Task<bool> SendSerialStringAsync(string portName, string data)
    {
        if (_serialPorts.TryGetValue(portName, out var serialComm))
        {
            return await serialComm.SendStringAsync(data);
        }
        _logger.LogWarning("Serial port {PortName} not found", portName);
        return false;
    }

    /// <summary>
    /// 发送串口字节数据
    /// </summary>
    public async Task<bool> SendSerialBytesAsync(string portName, byte[] data)
    {
        if (_serialPorts.TryGetValue(portName, out var serialComm))
        {
            return await serialComm.SendBytesAsync(data);
        }
        _logger.LogWarning("Serial port {PortName} not found", portName);
        return false;
    }

    /// <summary>
    /// 发送串口十六进制数据
    /// </summary>
    public async Task<bool> SendSerialHexAsync(string portName, string hexData)
    {
        if (_serialPorts.TryGetValue(portName, out var serialComm))
        {
            return await serialComm.SendHexStringAsync(hexData);
        }
        _logger.LogWarning("Serial port {PortName} not found", portName);
        return false;
    }

    #endregion

    #region TCP Communication Methods

    /// <summary>
    /// 启动TCP服务器
    /// </summary>
    public async Task<bool> StartTcpServerAsync(int port)
    {
        try
        {
            var key = $"server_{port}";
            if (_tcpConnections.ContainsKey(key))
            {
                _logger.LogWarning("TCP server on port {Port} is already running", port);
                return true;
            }

            var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
            var tcpComm = new ReactiveTcpCommunication(
                port, 
                true, 
                loggerFactory.CreateLogger<ReactiveTcpCommunication>(), 
                _messageBus);

            var success = await tcpComm.StartAsync();
            if (success)
            {
                _tcpConnections[key] = tcpComm;
                SetupTcpMonitoring(tcpComm, key);
                _statusSubject.OnNext($"TCP server started on port {port}");
            }

            return success;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to start TCP server on port {Port}", port);
            return false;
        }
    }

    /// <summary>
    /// 连接TCP客户端
    /// </summary>
    public async Task<bool> ConnectTcpClientAsync(string host, int port)
    {
        try
        {
            var key = $"client_{host}_{port}";
            if (_tcpConnections.ContainsKey(key))
            {
                _logger.LogWarning("TCP client to {Host}:{Port} is already connected", host, port);
                return true;
            }

            var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
            var tcpComm = new ReactiveTcpCommunication(
                port, 
                false, 
                loggerFactory.CreateLogger<ReactiveTcpCommunication>(), 
                _messageBus, 
                host);

            var success = await tcpComm.StartAsync();
            if (success)
            {
                _tcpConnections[key] = tcpComm;
                SetupTcpMonitoring(tcpComm, key);
                _statusSubject.OnNext($"TCP client connected to {host}:{port}");
            }

            return success;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to connect TCP client to {Host}:{Port}", host, port);
            return false;
        }
    }

    /// <summary>
    /// 发送TCP字符串数据
    /// </summary>
    public async Task<bool> SendTcpStringAsync(string data, string? clientId = null)
    {
        var tcpComm = _tcpConnections.Values.FirstOrDefault();
        if (tcpComm != null)
        {
            return await tcpComm.SendStringAsync(data, clientId);
        }
        _logger.LogWarning("No TCP connections available");
        return false;
    }

    /// <summary>
    /// 广播TCP字符串数据
    /// </summary>
    public async Task<int> BroadcastTcpStringAsync(string data)
    {
        var serverComm = _tcpConnections.Values.FirstOrDefault(tcp => tcp.IsServer);
        if (serverComm != null)
        {
            var bytes = System.Text.Encoding.UTF8.GetBytes(data);
            return await serverComm.BroadcastAsync(bytes);
        }
        _logger.LogWarning("No TCP server available for broadcast");
        return 0;
    }

    /// <summary>
    /// 停止TCP通讯
    /// </summary>
    public async Task StopTcpAsync()
    {
        var connections = _tcpConnections.ToList();
        _tcpConnections.Clear();
        
        foreach (var kvp in connections)
        {
            await kvp.Value.StopAsync();
            await kvp.Value.DisposeAsync();
            _statusSubject.OnNext($"TCP connection {kvp.Key} stopped");
        }
    }

    #endregion

    #region UDP Communication Methods

    /// <summary>
    /// 启动UDP通讯
    /// </summary>
    public async Task<bool> StartUdpAsync(int localPort, string? remoteHost = null, int? remotePort = null)
    {
        try
        {
            var key = $"udp_{localPort}";
            if (_udpConnections.ContainsKey(key))
            {
                _logger.LogWarning("UDP on port {Port} is already running", localPort);
                return true;
            }

            var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
            var udpComm = new ReactiveUdpCommunication(
                localPort, 
                loggerFactory.CreateLogger<ReactiveUdpCommunication>(), 
                _messageBus,
                remoteHost,
                remotePort);

            var success = await udpComm.StartAsync();
            if (success)
            {
                _udpConnections[key] = udpComm;
                SetupUdpMonitoring(udpComm, key);
                _statusSubject.OnNext($"UDP started on port {localPort}");
            }

            return success;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to start UDP on port {Port}", localPort);
            return false;
        }
    }

    /// <summary>
    /// 发送UDP字符串数据
    /// </summary>
    public async Task<bool> SendUdpStringAsync(string host, int port, string data)
    {
        var udpComm = _udpConnections.Values.FirstOrDefault();
        if (udpComm != null)
        {
            return await udpComm.SendStringAsync(data, host, port);
        }
        _logger.LogWarning("No UDP connections available");
        return false;
    }

    /// <summary>
    /// 广播UDP字符串数据
    /// </summary>
    public async Task<bool> BroadcastUdpStringAsync(int port, string data)
    {
        var udpComm = _udpConnections.Values.FirstOrDefault();
        if (udpComm != null)
        {
            return await udpComm.BroadcastStringAsync(data, port);
        }
        _logger.LogWarning("No UDP connections available");
        return false;
    }

    /// <summary>
    /// 停止UDP通讯
    /// </summary>
    public async Task StopUdpAsync()
    {
        var connections = _udpConnections.ToList();
        _udpConnections.Clear();
        
        foreach (var kvp in connections)
        {
            await kvp.Value.StopAsync();
            await kvp.Value.DisposeAsync();
            _statusSubject.OnNext($"UDP connection {kvp.Key} stopped");
        }
    }

    #endregion

    #region Status and Monitoring Methods

    /// <summary>
    /// 打印连接状态
    /// </summary>
    public async Task PrintConnectionStatusAsync()
    {
        Console.WriteLine($"📟 Serial Ports ({_serialPorts.Count}):");
        foreach (var kvp in _serialPorts)
        {
            var status = kvp.Value.IsConnected ? "Connected" : "Disconnected";
            Console.WriteLine($"  {kvp.Key}: {status} @ {kvp.Value.BaudRate} baud");
        }

        Console.WriteLine($"🔗 TCP Connections ({_tcpConnections.Count}):");
        foreach (var kvp in _tcpConnections)
        {
            var tcp = kvp.Value;
            var type = tcp.IsServer ? "Server" : "Client";
            var status = tcp.IsConnected ? "Connected" : "Disconnected";
            Console.WriteLine($"  {kvp.Key}: {type} - {status} on port {tcp.Port}");
        }

        Console.WriteLine($"📡 UDP Connections ({_udpConnections.Count}):");
        foreach (var kvp in _udpConnections)
        {
            var udp = kvp.Value;
            var status = udp.IsListening ? "Listening" : "Stopped";
            Console.WriteLine($"  {kvp.Key}: {status} on port {udp.LocalPort}");
        }

        await Task.CompletedTask;
    }

    /// <summary>
    /// 打印系统状态
    /// </summary>
    public async Task PrintSystemStatusAsync()
    {
        var now = DateTime.Now;
        Console.WriteLine($"⏰ System Time: {now:yyyy-MM-dd HH:mm:ss}");
        Console.WriteLine($"🖥️ Platform: {Environment.OSVersion}");
        Console.WriteLine($"🔌 Available Serial Ports: {string.Join(", ", ReactiveSerialCommunication.GetAvailablePorts())}");
        Console.WriteLine($"📊 Active Connections: Serial={_serialPorts.Count}, TCP={_tcpConnections.Count}, UDP={_udpConnections.Count}");
        Console.WriteLine($"💾 Memory Usage: {GC.GetTotalMemory(false) / 1024 / 1024:F1} MB");
        
        await Task.CompletedTask;
    }

    private void SetupStatusMonitoring()
    {
        // 监控消息总线的健康状态
        var healthSubscription = _messageBus.HealthStatus
            .DistinctUntilChanged()
            .Subscribe(isHealthy =>
            {
                _statusSubject.OnNext($"Message bus health: {(isHealthy ? "Healthy" : "Unhealthy")}");
            });

        _subscriptions.Add(healthSubscription);
    }

    private void SetupSerialMonitoring(ReactiveSerialCommunication serialComm)
    {
        var statusSubscription = serialComm.StatusChanges
            .Subscribe(status =>
            {
                _statusSubject.OnNext($"Serial {status.PortName}: {status.Status} - {status.Description}");
            });

        _subscriptions.Add(statusSubscription);
    }

    private void SetupTcpMonitoring(ReactiveTcpCommunication tcpComm, string key)
    {
        var statusSubscription = tcpComm.StatusChanges
            .Subscribe(status =>
            {
                var clientInfo = string.IsNullOrEmpty(status.ClientId) ? "" : $" (Client: {status.ClientId})";
                _statusSubject.OnNext($"TCP {key}: {status.Status} - {status.Description}{clientInfo}");
            });

        _subscriptions.Add(statusSubscription);
    }

    private void SetupUdpMonitoring(ReactiveUdpCommunication udpComm, string key)
    {
        var statusSubscription = udpComm.StatusChanges
            .Subscribe(status =>
            {
                _statusSubject.OnNext($"UDP {key}: {status.Status} - {status.Description}");
            });

        _subscriptions.Add(statusSubscription);
    }

    #endregion

    public async ValueTask DisposeAsync()
    {
        // 关闭所有连接
        await StopTcpAsync();
        await StopUdpAsync();
        
        var serialPorts = _serialPorts.ToList();
        _serialPorts.Clear();
        foreach (var kvp in serialPorts)
        {
            await kvp.Value.DisposeAsync();
        }

        // 清理订阅
        foreach (var subscription in _subscriptions)
        {
            subscription.Dispose();
        }
        _subscriptions.Clear();

        // 清理动态数据流主题
        _serialDataSubject?.Dispose();
        _tcpDataSubject?.Dispose();
        _udpDataSubject?.Dispose();
        _statusSubject?.Dispose();
        
        _logger.LogInformation("Communication manager disposed");
    }
}